iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 9
1
自我挑戰組

Golang魔法使 ─ 30天從零開始學習Go語言 | 比Python還簡單 | 理科生一定學得會 | 文科生不好說系列 第 9

#9 映射 Map ── 雪兔:除非是有魔法的人否則根本辦不到的 | Golang魔法使

  • 分享至 

  • xImage
  •  

這次小櫻遇到一個非常兇猛的Golang牌,究竟是什麼Golang牌可以把企鵝大王給弄倒呢?

我們先前提到的陣列與切片都是以整數為鍵值,而這次要介紹的複合型態,可以「不以整數為鍵值」,而這麼兇猛的卡牌即為「Map」

這個功能其實是可以用 Array 加一些黑科技實作出來,但因為太麻煩而且太常用,所以Golang直接對Map做原生支援

宣告一個 Map

先不管 Map 後面的原理到底是什麼,我們直接宣告一個來試試

package main
import "fmt"
func main(){
    // 建立一個由 string 映射到 int 的 map
    tall := make(map[string]int)
    tall["小櫻"] = 153
    tall["知世"] = 155
    tall["小狼"] = 156
    fmt.Println(tall["小櫻"])
    fmt.Println(tall["知世"])
    fmt.Println(tall["小狼"])
}

執行結果:
153
155
156

如此一來變可以很快地建立一個以字串為鍵(key)的陣列(?)

長得很像陣列,用起來也很像陣列,但是在Golang中稱為Map,python中稱為Dictionary(字典)、Javascript中稱為Object(物件)、PHP中稱為Associative array(關聯陣列),總之又是一個各家自己看心情命名的東西。

更簡短的宣告

然而,剛剛所用的方法是否太過麻煩!因此有更簡短的宣告方法

package main
import "fmt"
func main(){
    // 更簡短地建立一個由 string 映射到 int 的 map
    tall := map[string]int{
        "小櫻" : 153,
        "知世" : 155,
        "小狼" : 156,
    }
    fmt.Println(tall["小櫻"])
}

執行結果:
153

檢查該鍵是否存在

在存取時想確定該鍵是否存在該怎麼做呢?

其實可以利用兩個回傳值去存取,第一個會回傳「對應的值」,第二個會回傳「布林值」用來表示該鍵是否存在

package main
import "fmt"
func main(){
    // 更快地建立一個由 string 映射到 int 的 map
    tall := map[string]int{
        "小櫻" : 153,
        "知世" : 155,
        "小狼" : 156,
    }
    val, ok := tall["小櫻"]
    fmt.Println(val, ok)
    val, ok  = tall["小可"]
    fmt.Println(val, ok)
}

執行結果:
153 true
0 false

如果該鍵並不存在,則在讀取該值時其實並不會出錯,而是會以預設值充當對應值回傳,這與部份魔法語言的特性不太一樣

如果只是想確認該值是否存在而不想知道該值,則可以在回傳對應值的部分設為 _,以免魔仗因為你沒使用宣告出來的變數而噴錯

package main
import "fmt"
func main(){
    // 更快地建立一個由 string 映射到 int 的 map
    tall := map[string]int{
        "小櫻" : 153,
        "知世" : 155,
        "小狼" : 156,
    }
    _, ok := tall["小狼"]
    fmt.Printf("tall[\"小狼\"] 存在嗎?%t", ok) // 第 11 行
}

執行結果:
tall["小狼"] 存在嗎?true

補充一點:在第 11 行 print 的地方當我們要 print 出雙引號時,為了必免被誤認成字串用的雙引號,我們可以在雙引號前加上反斜線 \ 去告訴魔仗這是一般的字不是識別字串起頭結尾的字

走訪

如同前兩天所教的課程(array 和 slice),map 也可以透過 for + range 的方式進行走訪

package main
import "fmt"
func main(){
    // 更快地建立一個由 string 映射到 int 的 map
    tall := map[string]int{
        "小櫻" : 153,
        "知世" : 155,
        "小狼" : 156,
    }
    for k, v := range tall{
        fmt.Printf("%s的身高是:%dcm\n", k, v)
    }
}

執行結果:
小櫻的身高是:153cm
知世的身高是:155cm
小狼的身高是:156cm

注意:走訪時的順序跟加入的順序無關
順序完全是以魔仗底層的咒語依效能而決定

For迴圈走訪補充

(9/13補充)
利用 for 迴圈走訪時,通常會用 key, value 去接 range 的回傳值,但是,其實也可以只用一個參數,而這個參數預設是 key,所以如果只想走訪 key 時就可以不用使用 k, _ := range xxx 這種寫法,可以直接寫成 k := range xxx

package main
import "fmt"
func main(){
    tall := map[string]int{
        "小櫻" : 153,
        "知世" : 155,
        "小狼" : 156,
    }

    for k := range tall{
        fmt.Println(k)
    }
}

執行結果:
小櫻
知世
小狼

刪除一對鍵值

除了可以新增和修改 map 外,也可以刪除一對鍵值,做法是使用 delete()

package main
import "fmt"
func main(){
    // 更快地建立一個由 string 映射到 int 的 map
    tall := map[string]int{
        "小櫻" : 153,
        "知世" : 155,
        "小狼" : 156,
    }
    delete(tall, "小櫻")  // 將小櫻從 map 中刪除
    for k, v := range tall{
        fmt.Printf("%s的身高是:%dcm\n", k, v)
    }
}

執行結果:
知世的身高是:155cm
小狼的身高是:156cm

後記

給大家看一下唬爛王山崎↓

而且整部動漫只有李小狼和小櫻會信,笑死,難道是因為同為魔法使的關係,吔~不對,李小狼是魔法使?

話說怎麼最近這幾天的文都不夠ㄎㄧㄤ?吸太少

邦友的按讚是我發文的動力 ,希望各位邦友動動手按個讚!如果有不懂的地方也可以在本文底下留言互動哦!

想了解Map的運作原理可以參考

  1. How the Go runtime implements maps efficiently (without generics)
  2. Golang官方 map.go

如果想稍微了解的可以搜尋 Hash map,hash 中文稱雜湊,可以將不同字串轉成不同數字(理想上),利用這個特性再把字串映射到 Array 上,最後為了避免碰撞,再透過 linked list 或紅黑樹等神祕資料結構去儲存。但是這一部份也許以後也不會提到。如果今天主題是 C 語言,就沒有原生的 Map 可以使用;如果是 java 則是額外包成一個物件來用;rust 也是用額外的插件去支持。

Golang 則是直接做原生支持,簡單方便又好用,雖然我覺得 rust 的 hashmap 真的是快掉炸掉就是了。

接下來的課程會越來越難,請新來的魔法使做好心理準備。這系列文進度會越來越快,呈指數型成長。

為了讓新來的魔法使能跟上進度就來出個題目好了

練習1:

利用迴圈印出九九乘法表
提示:for迴圈內可以再加for迴圈

#5 For 迴圈流程控制 | Golang魔法使

練習2:

不呼叫golang提供的排序函式下,由小到到大排序一個整數陣列

arr := [...]int{10, 4, 5, 3, 7, 1, 9, 8}

#7 陣列 Array | Golang魔法使

練習這兩題後應該就能繼續往後的課程了

本文多數圖片來自:
庫洛魔法使第一季第十三集


上一篇
#8 切片 Slice | Golang 魔法使
下一篇
#10 指標 Pointer | Golang魔法使
系列文
Golang魔法使 ─ 30天從零開始學習Go語言 | 比Python還簡單 | 理科生一定學得會 | 文科生不好說30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
alan_jhu
iT邦新手 5 級 ‧ 2021-06-27 21:17:15

很用心的教學文
推一個

付個插入排序

func sortArr() {
	arr := []int{10, 4, 5, 3, 7, 1, 9, 8}

	for i := 1; i < len(arr); i++ {
		k := i
		for k > 0 && arr[k-1] > arr[k] {
			swap(arr, k, k-1)
			k--
		}
	}
}

func swap(arr []int, a int, b int) {
	temp := arr[a]
	arr[a] = arr[b]
	arr[b] = temp
}

我要留言

立即登入留言